<template>
  <div class="calendar-container">
    <div :class="{ 'calendar-holidaystyle': isHoliday, calendar: true }">
      <div class="calendar-wrapper">
        <div class="calendar-box">
          <div class="header-box">
            <dropdown
              @change="changeYear"
              class="header-block-selectbox3"
              :data="yearsArr"
              v-model:value="yearVal"
            >
            </dropdown>
            <div class="header-block-2">
              <div
                v-if="
                  curDate.getFullYear() > startOfYear ||
                  (curDate.getFullYear() == startOfYear &&
                    curDate.getMonth() > 0)
                "
                class="calendar-prev-month"
                @click="changeMonth(-1)"
              ></div>
              <dropdown
                @change="changeMonth"
                v-model:value="monthVal"
                class="header-block-selectbox2"
                :data="monthArr"
              >
              </dropdown>
              <div
                class="calendar-next-month"
                v-if="
                  curDate.getFullYear() < endOfYear ||
                  (curDate.getFullYear() == endOfYear &&
                    curDate.getMonth() < 11)
                "
                @click="changeMonth(1)"
              ></div>
            </div>
            <dropdown
              @change="changeFestival"
              v-model:value="festiVal"
              :disabled="festiDisabled"
              class="header-block-selectbox3"
              :data="festivalArr"
            >
            </dropdown>
            <div class="back-today" @click="curMonth">返回今天</div>
          </div>
          <table class="calendar-panel">
            <thead>
              <th v-for="(item, index) in weekArr" :key="index">
                {{ item }}
              </th>
            </thead>
            <tbody>
              <tr v-for="row in rowCount" :key="row">
                <td
                  v-for="col in colCount"
                  :key="col"
                  :title="
                    formatDate(
                      dataList[(row - 1) * colCount + col - 1].date,
                      'YYYY年M月D日'
                    )
                  "
                >
                  <div
                    class="cell-inner-box"
                    @click="
                      changeDate(dataList[(row - 1) * colCount + col - 1])
                    "
                    :class="[
                      isWeekend(dataList[(row - 1) * colCount + col - 1].date)
                        ? 'cell-weekend'
                        : '',
                      formatDate(curDate) ==
                      formatDate(dataList[(row - 1) * colCount + col - 1].date)
                        ? 'cell-selected'
                        : '',
                      dataList[(row - 1) * colCount + col - 1].isToday
                        ? 'cell-today'
                        : '',

                      dataList[(row - 1) * colCount + col - 1].cur == 0
                        ? 'cur-date '
                        : 'cell-other-month',
                      getHolidayScheduleInfo(
                        dataList[(row - 1) * colCount + col - 1]
                      ),
                    ]"
                  >
                    <!--   -->
                    <div
                      :class="[
                        'holiday-sign',
                        dataList[(row - 1) * colCount + col - 1].isOnDuty
                          ? 'cell-holiday-sign'
                          : '',
                      ]"
                      v-if="
                        dataList[(row - 1) * colCount + col - 1].isOnDuty ||
                        dataList[(row - 1) * colCount + col - 1].isRest
                      "
                    >
                      {{
                        dataList[(row - 1) * colCount + col - 1].isOnDuty
                          ? "班"
                          : "休"
                      }}
                    </div>
                    <div class="cell-daynumber">
                      {{ dataList[(row - 1) * colCount + col - 1].num }}
                    </div>
                    <!-- 两边预留空格居中 
                      {{ " 初三 " }}
                      -->
                    <div class="cell-almanac">
                      {{
                        getFestivalText(
                          dataList[(row - 1) * colCount + col - 1].lunar
                        )
                      }}
                    </div>
                  </div>
                </td>
              </tr>
            </tbody>
          </table>
        </div>
        <div class="calendar-box-right">
          <div class="calendar-right-date">{{ formatDate(curDate) }}</div>
          <div class="calendar-right-day">{{ formatDate(curDate, "D") }}</div>
          <div class="calendar-right-lunar">
            <div>
              {{ cellDate.IMonthCn + "" + cellDate.IDayCn }}
            </div>
            <div>{{ cellDate.gzYear }}年 {{ cellDate.Animal }}</div>
            <div>{{ cellDate.gzMonth }}月 {{ cellDate.gzDay }}日</div>
          </div>
          <div
            class="calendar-right-holiday"
            v-if="getFestivalText(cellDate, 1)"
          >
            {{ getFestivalText(cellDate, 1) }}
          </div>
          <CalendarSuggestion></CalendarSuggestion>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import {
  ref,
  computed,
  watch,
  reactive,
  onMounted,
  onBeforeUpdate,
  onBeforeMount,
} from "vue";
import moment, { Moment } from "moment";
import { LunarType } from "@/types/enum";
import {
  isWeekend,
  lunar2solar,
  solar2lunar,
  formatDate,
  isValidDate,
  getHolidayDate,
} from "@/util/index";
import {
  startOfYear,
  endOfYear,
  rowCount,
  colCount,
  holidayStartOfYear,
} from "./constant";

import Dropdown from "../dropdown/Dropdown.vue";
import CalendarSuggestion from "./CalendarSuggestion.vue";
const emit = defineEmits(["change"]);
interface Props {
  mondayFirst: boolean;
}
const props = withDefaults(defineProps<Props>(), {
  mondayFirst: true,
});

let now: Date = new Date();

let weekArr = ref(["日", "一", "二", "三", "四", "五", "六"]);

let months: Array<CellType> = Array.from({ length: 12 }, (k, v) => {
  return { label: `${v + 1}月`, value: v + 1 + "" } as CellType;
});
let monthArr = reactive(months);
let isHoliday = ref(false);
let years: Array<CellType> = Array.from(
  { length: endOfYear - startOfYear + 1 },
  (k, v) => {
    return {
      label: `${startOfYear + v}年`,
      value: startOfYear + v + "",
    } as CellType;
  }
);
let yearsArr = ref(years);
let cellDate: CellDateLunar = solar2lunar(new Date());
let curDate = ref<Date>(new Date());

let yearVal = ref(0);
let festiVal = ref(0);
let festiDisabled = ref(false);
let monthVal = ref(curDate.value.getMonth());

let holidayScheduleArr: Array<HolidayDate> = reactive([]);

let festivalArr: Array<CellType> = reactive<CellType[]>([
  { label: "假期安排", value: "" },
  { label: "元旦节", value: "01-01" },
  { label: "除夕", value: "", lunar: true, type: LunarType.Eve },
  { label: "春节", value: "01-01", lunar: true },
  { label: "劳动节", value: "05-01" },
  { label: "端午节", value: "05-05", lunar: true },
  { label: "中秋节", value: "08-15", lunar: true },
  { label: "国庆节", value: "10-01" },
]);

const getHolidayScheduleInfo = (cell: CellDate) => {
  let target = holidayScheduleArr.find((item) => {
    if (formatDate(item.date) == formatDate(cell.date)) {
      return item;
    }
  });
  if (target) {
    target.isOnDuty ? (cell.isOnDuty = true) : (cell.isRest = true);
    return target.isOnDuty ? "cell-onduty" : "cell-rest";
  }
};

/**
 * @param date 当前月的日期
 */
const getDateArr = (date: Date): Array<CellDate> => {
  let startTheMonth = moment(date).startOf("month");
  let endTheMonth = moment(date).endOf("month");
  let today: Date = new Date();
  let current: Array<CellDate> = Array.from(
    { length: endTheMonth.date() },
    (k, v) => {
      let target: Moment = moment(startTheMonth).add(v, "days");
      let date: Date = target.toDate();

      let lunar: CellDateLunar = solar2lunar(date);
      return {
        num: v + 1,
        date,
        lunar,
        isToday: formatDate(date) == formatDate(today),
        cur: 0,
      };
    }
  );
  let lastCount: number = startTheMonth.day();
  if (props.mondayFirst) {
    lastCount = startTheMonth.day() == 0 ? rowCount : startTheMonth.day() - 1;
  }
  let last: Array<CellDate> = Array.from({ length: lastCount }, (k, v) => {
    let target: Moment = moment(startTheMonth).subtract(lastCount - v, "days");
    return {
      num: target.date(),
      date: target.toDate(),
      lunar: solar2lunar(target.toDate()),
      cur: -1,
    };
  });
  let next: Array<CellDate> = Array.from(
    { length: rowCount * colCount - (last.length + current.length) },
    (k, v: number) => {
      let target: Moment = moment(endTheMonth).add(v + 1, "days");
      return {
        num: v + 1,
        date: target.toDate(),
        lunar: solar2lunar(target.toDate()),
        cur: 1,
      };
    }
  );
  return [...last, ...current, ...next];
};

const changeDropdown = async (init: boolean = false) => {
  let month = curDate.value.getMonth();
  let year = curDate.value.getFullYear();
  let oldYearIndex = yearVal.value;
  let yearIndex = yearsArr.value.findIndex(
    (item) => item.value === year.toString()
  );
  yearVal.value = yearIndex < 0 ? 0 : yearIndex;
  festiDisabled.value = year < holidayStartOfYear;
  monthVal.value = month;
  emit("change", curDate.value);
  //切换了年份,节假日需要重新计算
  // if (init || oldYearIndex !== yearVal.value) {

  // }
};

/**
 * LunarType.Eve：除夕 。日期不确定，可能是农历十二月二十九，也可能是农历十二月三十。
 * 采用春节倒推一天计算
 */
const initFestivalDate = () => {
  festivalArr.forEach((cell: CellType, index) => {
    if (index < 1) return;
    let year = curDate.value.getFullYear();
    let month = cell.value.split("-")[0],
      day = cell.value.split("-")[1];
    if (cell.lunar) {
      let date: Date;
      if (cell.type == LunarType.Eve) {
        let newYear: Date = lunar2solar(year, 1, 1);
        date = moment(newYear).subtract(1, "days").toDate();
      } else {
        date = lunar2solar(year, Number(month), Number(day));
      }
      if (!isValidDate(date)) {
        throw Error("错误");
      }
      cell.date = date;
    } else {
      let date = new Date(year, parseInt(month) - 1, parseInt(day));
      if (!isValidDate(date)) {
        throw Error("错误");
      }
      cell.date = date;
    }
  });
};

onMounted(async () => {
  changeDropdown(true);
});

// 初始化 日历列表
let dataList = ref(getDateArr(curDate.value) as Array<CellDate>);

watch(
  () => props.mondayFirst,
  (newValue, oldValue) => {
    if (props.mondayFirst) {
      weekArr.value = ["一", "二", "三", "四", "五", "六", "日"];
    } else {
      weekArr.value = ["日", "一", "二", "三", "四", "五", "六"];
    }
    dataList.value = getDateArr(curDate.value);
  },
  { immediate: true }
);

watch(
  () => curDate.value,
  async (newVal, oldVal) => {
    let year = curDate.value.getFullYear();
    let momth = curDate.value.getMonth();

    if (oldVal == undefined || oldVal.getFullYear() !== year) {
      initFestivalDate();
    }
    let curHoliday = await getHolidayDate(year);
    let preHoliday = await getHolidayDate(year - 1);
    let nextHoliday = await getHolidayDate(year + 1);
    holidayScheduleArr = [...preHoliday, ...curHoliday, ...nextHoliday];
  },
  { immediate: true, deep: true }
);

const curMonth = () => {
  //TODO 直接设置当天不是节假日
  festiVal.value = 0;
  curDate.value = now;
  dataList.value = getDateArr(curDate.value);

  emit("change", curDate.value);
  changeDropdown();
};
const changeMonth = async (val: any = 1, index: number = 0) => {
  if (typeof val == "number") {
    //左右切换月份
    curDate.value = moment(curDate.value).add(val, "months").toDate();
  } else {
    //月份下拉框
    monthVal.value = index;
    curDate.value = new Date(
      curDate.value.getFullYear(),
      val.value - 1,
      curDate.value.getDate()
    );

    dataList.value = getDateArr(curDate.value);
  }
  cellDate = solar2lunar(curDate.value);
  dataList.value = getDateArr(curDate.value);
  changeDropdown();
  festiVal.value = 0;
  isHoliday.value = false;
};

const changeYear = (val: CellType, index: number) => {
  curDate.value = new Date(
    parseInt(val.value),
    curDate.value.getMonth(),
    curDate.value.getDate()
  );
  cellDate = solar2lunar(curDate.value);
  dataList.value = getDateArr(curDate.value);
  changeDropdown(true);
  festiVal.value = 0;
};
const changeFestival = (val: CellType, index: number) => {
  if (!val || val.date === undefined) {
    isHoliday.value = false;
    return;
  }
  curDate.value = val.date;
  dataList.value = getDateArr(curDate.value);
  festiVal.value = index;

  isHoliday.value = index == 2; //除夕换肤
  changeDropdown();
};

let changeDate = (cell: CellDate) => {
  curDate.value = cell.date;
  cellDate = solar2lunar(cell.date);
  dataList.value = getDateArr(curDate.value);
  emit("change", curDate.value);
};

const getFestivalText = (data: any, type: number = 0) => {
  if (type == 0) {
    return data.festival || data.lunarFestival || data.Term || data.IDayCn;
  } else {
    return (
      data.otherFestival || data.festival || data.lunarFestival || data.Term
    );
  }
};
</script>

<style>
.calendar-container {
  width: 560px;
  word-wrap: break-word;
  word-break: break-all;
  color: #333;
  font-size: 13px;
  line-height: 21px;
  border-collapse: collapse;
  margin-bottom: 20px;
  font: 13px/21px Arial, sans-serif;
}

.calendar {
  margin: 0 -16px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
  border-radius: 16px;
}

.calendar-wrapper {
  height: 472px;
  position: relative;
  z-index: 1;
  display: flex;
}

.calendar-box {
  width: 480px;
  height: 100%;
  padding: 15px 15px 0;
  border-radius: 16px 0 0 16px;
  border: 2px solid #4e6ef2;
  border-right: none;
  box-sizing: border-box;
}

.calendar-box-right {
  height: 100%;
  color: #fff;
  text-align: center;
  border-radius: 0 16px 16px 0;
  background: #4e6ef2;
  width: 112px;
}

.header-box {
  position: relative;
  display: flex;
  height: 30px;
  zoom: 1;
}

.header-block-1 {
  width: 96px;
  margin-right: 9px;
}

.header-block-2 {
  position: relative;
  width: 80px;
  padding: 0 34px;
  z-index: 1;
  margin-right: 9px;
}

.header-block-selectbox2 {
  width: 90px;
}

.header-block-selectbox3 {
  width: 96px;
  margin-right: 9px;
}

.calendar-prev-month,
.calendar-next-month {
  position: absolute;
  width: 30px;
  height: 30px;
  text-align: center;
  line-height: 30px;
  color: #9195a3;
  font-size: 16px;
  cursor: pointer;
}

.calendar-prev-month {
  left: 0;
  background: url(../../assets/arrow_left.png) no-repeat center;
  background-size: 16px auto;
}

.calendar-next-month {
  top: 0;
  right: 0;
  background: url(../../assets/arrow_right.png) no-repeat center;
  background-size: 16px auto;
}

.calendar-panel {
  margin-bottom: 14px;
  border-collapse: collapse;
  /* 头 */
  margin-top: 14px;
  /* justify-content: center;
    align-items: center;
    height: 36px;
    display: flex; */
}

.calendar-panel thead th {
  width: 64px;
  height: 13px;
  padding: 1px;
  justify-content: center;
  align-items: center;
  font-family: MicrosoftYaHei;
  font-size: 13px;
  color: #333333;
  line-height: 13px;
}

.calendar-panel tbody tr td {
  padding: 2px;
}

.cell-inner-box {
  /* 
  color: rgba(0, 0, 0, 0.65);
  text-align: center; */
  display: flex;
  position: relative;
  justify-content: center;
  align-content: center;
  align-items: center;
  flex-direction: column;
  border-radius: 6px;
  cursor: pointer;
  width: 60px;
  height: 56px;
  padding: 4px 2px 2px 2px;
  box-sizing: border-box;
  border: 2px solid transparent;
  overflow: hidden;
  line-height: 1;
  zoom: 1;
}

.cell-selected,
.cell-inner-box:hover {
  border: 2px solid #bdbfc8;
}

.cell-other-month {
  filter: alpha(opacity=40);
  opacity: 0.4;
}

.holiday-sign {
  position: absolute;
  left: 4px;
  top: 4px;
  color: #f73131;
  font-size: 12px;
  line-height: 12px;
}

.cell-holiday-sign {
  color: #636775;
}

.cell-rest {
  background: #fde3e4;
}

.cell-onduty {
  background: #f5f5f6;
}

.cell-daynumber {
  height: 22px;
  font-size: 18px;
  color: #000;
}

.cell-weekend .cell-daynumber,
.cell-festival .cell-daynumber {
  color: #f73131;
}

.cell-almanac {
  color: #333;
  font-size: 12px;
}

.date-btn {
  background-color: #535bf2;
  color: #fff;
  margin-left: 10px;
}

.back-today {
  position: absolute;
  right: 0;
  margin-right: 2px;
  width: 68px;
  height: 30px;
  line-height: 30px;
  text-align: center;
  background: #f5f5f6;
  border-radius: 6px;
  color: #333;
  cursor: pointer;
}

.back-today:hover {
  color: #315efb;
  background: #f0f0f1;
}

.cell-today {
  border: 2px solid #4e6ef2 !important;
}

.cell-almanac {
  color: #333;
  font-size: 12px;
}

.calendar-right-date {
  line-height: 45px;
  font-size: 13px;
}

.calendar-right-day {
  position: relative;
  width: 80px;
  height: 80px;
  margin: 0 auto;
  line-height: 80px;
  font-size: 52px;
  background: rgba(255, 255, 255, 0.5);
  border-radius: 12px;
}

.calendar-right-lunar {
  margin-top: 6px;
}

.calendar-right-holiday {
  position: relative;
  margin-top: 13px;
  padding-left: 22px;
  padding-right: 14px;
  text-align: justify;
  color: #fff;
  font-size: 12px;
  line-height: 16px;
}

.calendar-right-holiday::before {
  content: "";
  position: absolute;
  top: 6px;
  left: 16px;
  width: 3px;
  height: 3px;
  background: #fff;
  border-radius: 50%;
}

/* 节假日 */
.calendar-holidaystyle .calendar-box {
  border-color: #eb3636;
}

.cell-festival.cell-selected,
.cell-festival:hover {
  border: 2px solid #f38686 !important;
}

.calendar-holidaystyle .calendar-box-right {
  background: #eb3636;
}
</style>
